package cn.tb.ymcc.service.impl;

import cn.tb.ymcc.doc.CourseDoc;
import cn.tb.ymcc.domain.*;
import cn.tb.ymcc.dto.CourseDto;
import cn.tb.ymcc.feign.CourseSearchFeignClient;
import cn.tb.ymcc.feign.MediaFeignClient;
import cn.tb.ymcc.mapper.CourseMapper;
import cn.tb.ymcc.result.JSONResult;
import cn.tb.ymcc.service.*;
import cn.tb.ymcc.util.AssertUtil;
import cn.tb.ymcc.util.StrUtils;
import cn.tb.ymcc.vo.CourseDetailInfoVo;
import cn.tb.ymcc.vo.CourseItemVo;
import cn.tb.ymcc.vo.CourseOrderVo;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author tangbo
 * @since 2022-07-21
 */
@Service
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {

    @Autowired
    private ITeacherService teacherService;
    @Autowired
    private ICourseDetailService courseDetailService;
    @Autowired
    private ICourseResourceService courseResourceService;
    @Autowired
    private ICourseMarketService courseMarketService;
    @Autowired
    private ICourseTeacherService courseTeacherService;
    @Autowired
    private ICourseTypeService courseTypeService;
    @Autowired
    private ICourseSummaryService courseSummaryService;
    @Autowired
    private CourseSearchFeignClient courseSearchFeignClient;
    @Autowired
    private ICourseChapterService courseChapterService;
    @Autowired
    private MediaFeignClient mediaFeignClient;

    /**
     * 1.参数校验
     * 2.课程不能被注册
     *
     * 3.保存数据
     * 保存课程
     * 保存课程详情
     * 保存课程销售
     * 保存课程讲师
     * 保存课程资源
     * 初始化课程统计
     *
     * 课程类型表中的课程数+1
     *
     * @param dto
     */
    @Override
    @Transactional
    public void save(CourseDto dto) {
        Course course = dto.getCourse();
        CourseDetail courseDetail = dto.getCourseDetail();
        CourseMarket courseMarket = dto.getCourseMarket();
        CourseResource courseResource = dto.getCourseResource();
        List<Long> teacharIds = dto.getTeacharIds();
        //课程不能被注册=====================
        Course courseTmp = selectByName(course.getName());
        AssertUtil.isNull(courseTmp,"课程已经存在");

        //保存课程,做必要的参数的初始化 状态、讲师、谁来添加的课程==========================
        course.setStatus(Course.STATUS_OFFLINE);
        //@TODO 后面做了登录之后来补充,先写死
        course.setLoginId(1L);
        course.setLoginUserName("yhptest1");
        //stream流
        List<Teacher> teachers = teacherService.selectBatchIds(teacharIds);
        StringBuilder sb = new StringBuilder();
        teachers.forEach(teacher -> {
            sb.append(teacher.getName()).append(",");
        });
        course.setTeacherNames(sb.toString());
        insert(course);

        //保存课程详情===========================
        courseDetail.setId(course.getId());
        courseDetailService.insert(courseDetail);

        //保存课程销售===========================
        courseMarket.setId(course.getId());
        courseMarketService.insert(courseMarket);

        //保存课程讲师===========================
        teacharIds.forEach(id->{
            CourseTeacher courseTeacher = new CourseTeacher();
            courseTeacher.setCourseId(course.getId());
            courseTeacher.setTeacherId(id);
            courseTeacherService.insert(courseTeacher);
        });

        //保存课程资源===========================
        courseResource.setCourseId(course.getId());
        courseResourceService.insert(courseResource);

        //初始化课程统计===========================
        CourseSummary courseSummary = new CourseSummary();
        courseSummary.setId(course.getId());
        courseSummaryService.insert(courseSummary);

        //课程类型表中的课程数+1======================
        CourseType type = courseTypeService.selectById(course.getCourseTypeId());
        type.setTotalCount(type.getTotalCount()+1);
        courseTypeService.updateById(type);
    }

    private Course selectByName(String name) {
        EntityWrapper<Course> wrapper = new EntityWrapper<>();
        wrapper.eq("name",name);
        return selectOne(wrapper);
    }

    /**
     * 课程发布实现
     * 1.根据传过来的课程id查询是否存在
     * 2.修改课程状态为上架，修改上架时间
     * 3.把上传的课程以及相关信息保存到es
     *      3.1 在ymcc-api-search为service-search编写feign接口
     *      3.2 在课程微服务中，依赖ymcc-api-search
     *      3.3 使用feign远程调用search完成课程保存到Es中
     * @param courseId
     */
    @Override
    @Transactional
    public void saveCourse(Long courseId) {
        Course course = selectById(courseId);
        AssertUtil.isNotNull(course,"课程不存在");
        //判断查到的课程的状态是不是下架
        boolean offLine = course.getStatus() == Course.STATUS_OFFLINE;
        AssertUtil.isTrue(offLine,"课程状态不满足");
        //修改课程状态，修改上架时间
        course.setStatus(Course.STATUS_ONLINE);
        course.setOnlineTime(new Date());
        updateById(course);
        //保存课程相关内容到Es
        CourseType type = courseTypeService.selectById(course.getCourseTypeId());
        CourseMarket courseMarket = courseMarketService.selectById(course.getId());
        CourseSummary courseSummary = courseSummaryService.selectById(course.getId());
        CourseDoc courseDoc = new CourseDoc();
        BeanUtils.copyProperties(course,courseDoc);
        BeanUtils.copyProperties(courseMarket,courseDoc);
        BeanUtils.copyProperties(courseSummary,courseDoc);
        courseDoc.setCourseTypeName(type.getName());
        String chargeName = courseMarket.getCharge() == 1 ? "免费" : "收费";
        courseDoc.setChargeName(chargeName);
        JSONResult jsonResult = courseSearchFeignClient.saveCourse(courseDoc);
        //AssertUtil.isNotNull(jsonResult,"课程发布失败");
        AssertUtil.isTrue(jsonResult.isSuccess(),"课程发布失败");
    }

    /**
     * 课程下架
     * 1.校验
     * 2.修改课程状态为下架
     * 3.删除es中的数据
     * @param courseId
     */
    @Override
    public void offLineCourse(Long courseId) {
        Course course = selectById(courseId);
        AssertUtil.isNotNull(course,"下架课程不存在");
        //修改课程状态
        course.setStatus(Course.STATUS_OFFLINE);
        updateById(course);
        //删除es中相关数据
        JSONResult jsonResult = courseSearchFeignClient.deleteCourse(courseId);
        AssertUtil.isTrue(jsonResult.isSuccess(),"课程下架失败");
    }

    /**
     * 课程详情查询
     * @param courseId
     * @return
     */
    @Override
    public CourseDetailInfoVo searchCourseDetail(Long courseId) {
        //一堆校验
        AssertUtil.isNotNull(courseId,"请求非法");
        Course course = selectById(courseId);
        AssertUtil.isNotNull(course,"请求非法");
        boolean onLine = course.getStatus() == Course.STATUS_ONLINE;
        //课程没有上线,抛错
        AssertUtil.isTrue(onLine,"请求非法");

        CourseDetail courseDetail = courseDetailService.selectById(courseId);
        CourseMarket courseMarket = courseMarketService.selectById(courseId);
        CourseSummary courseSummary = courseSummaryService.selectById(courseId);
        //查询老师们
        EntityWrapper<CourseTeacher> twrapper = new EntityWrapper<>();
        twrapper.eq("course_id",courseId);
        List<CourseTeacher> courseTeachers = courseTeacherService.selectList(twrapper);
        //流式编程
        //List<Long> teacherIds = courseTeachers.stream().map(teacher -> teacher.getTeacherId()).collect(Collectors.toList());
        //List<Teacher> teachers = teacherService.selectBatchIds(teacherIds);
        List<Teacher> teachers = new ArrayList<>();
        courseTeachers.forEach(courseTeacher -> {
            Long teacherIds = courseTeacher.getTeacherId();
            Teacher teacher = teacherService.selectById(teacherIds);
            teachers.add(teacher);
        });
        //查询章节
        EntityWrapper<CourseChapter> cwrapper = new EntityWrapper<>();
        cwrapper.eq("course_id",courseId);
        List<CourseChapter> courseChapters = courseChapterService.selectList(cwrapper);
        //查询每一个章节查询对应的视频
        //1.media微服务编写controller查询章节视屏
        //2.为media服务编写Feign接口+降级方案
        //3.course微服务依赖media的Feign接口，调用media查询章节视屏
        courseChapters.forEach(courseChapter -> {
            JSONResult jsonResult = mediaFeignClient.searchMediaFiles(courseChapter.getId());
            if(jsonResult.isSuccess()&&jsonResult.getData()!=null){
                List<MediaFile> mediaFiles = JSONObject.parseArray(jsonResult.getData().toString(), MediaFile.class);
                mediaFiles.forEach(mediaFile -> {
                    mediaFile.setFileUrl(null);
                });
                courseChapter.getMediaFiles().addAll(mediaFiles);
            }
        });
        CourseDetailInfoVo vo = new CourseDetailInfoVo();
        vo.setCourse(course);
        vo.setCourseChapters(courseChapters);
        vo.setCourseMarket(courseMarket);
        vo.setCourseSummary(courseSummary);
        vo.setCourseDetail(courseDetail);
        vo.setTeachers(teachers);
        return vo;
    }

    /**
     * 程ids查询订单页数据
     * 1.校验参数
     * 2.业务校验
     * 3.根据课程id查出课程+销售相关
     * 4.把课程数据和销售相关信息封装CourseItemVo
     * 5.将封装好的List<CourseItemVo> 和 totalAmount封装成CourseOrderVo
     * @param courseIds
     * @return
     */
    @Override
    public CourseOrderVo searchOrerDetail(String courseIds) {
        List<Long> ids = StrUtils.splitStr2LongArr(courseIds);
        Set<Long> setIds = ids.stream().collect(Collectors.toSet());
        //1.校验参数
        AssertUtil.isNotNull(courseIds,"课程id为空");
        //2.业务校验
        boolean b = setIds.size() == ids.size();
        AssertUtil.isTrue(b,"请求非法");
        //3.根据课程id查出课程+销售相关
        List<CourseItemVo> courseInfos = new ArrayList<>();
        BigDecimal totalAmount = new BigDecimal(0);

        for (Long setId : setIds) {
            //4.把课程数据和销售相关信息封装CourseItemVo
            Course course = selectById(setId);
            AssertUtil.isNotNull(course,"课程不存在");
            //查到的课程必须是上线的
            boolean onLine = course.getStatus() == Course.STATUS_ONLINE;
            AssertUtil.isTrue(onLine,"课程没上线");
            CourseMarket courseMarket = courseMarketService.selectById(setId);
            AssertUtil.isNotNull(courseMarket,"非法请求");
            CourseItemVo courseItemVo = new CourseItemVo(course, courseMarket);
            courseInfos.add(courseItemVo);
            totalAmount = totalAmount.add(courseMarket.getPrice());
        }
        //5.将封装好的List<CourseItemVo> 和 totalAmount封装成CourseOrderVo
        return new CourseOrderVo(courseInfos,totalAmount);
    }
}
